package com.netsdk.apis;

import com.netsdk.common.ErrorCode;
import com.netsdk.common.Res;
import com.netsdk.demo.module.LoginModule;
import com.netsdk.lib.NetSDKLib;
import com.netsdk.lib.ToolKits;
import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;
import org.springframework.stereotype.Component;

import javax.swing.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: tracy
 * @Date: 2018/11/20 10:26
 * @Description:
 */
@Component
public class DeviceAPI {
    public static NetSDKLib netsdk 		= NetSDKLib.NETSDK_INSTANCE;
    public static NetSDKLib configsdk 	= NetSDKLib.CONFIG_INSTANCE;

    // 设备信息
    public static NetSDKLib.NET_DEVICEINFO_Ex m_stDeviceInfo = new NetSDKLib.NET_DEVICEINFO_Ex();
    // 设备断线通知回调
    private static DisConnect disConnect       = new DisConnect();
    // 网络连接恢复
    private static HaveReConnect haveReConnect = new HaveReConnect();

    private static boolean bInit    = false;
    private static boolean bLogopen = false;

    // 登陆句柄
    public static Map<String,NativeLong> loginHandleMap = new HashMap<String,NativeLong>();


    public static boolean init(NetSDKLib.fDisConnect disConnect, NetSDKLib.fHaveReConnect haveReConnect) {
        bInit = netsdk.CLIENT_Init(disConnect, new NativeLong(0));
        if(!bInit) {
            System.out.println("Initialize SDK failed");
            return false;
        }

        // 设置断线重连回调接口，设置过断线重连成功回调函数后，当设备出现断线情况，SDK内部会自动进行重连操作
        // 此操作为可选操作，但建议用户进行设置
        netsdk.CLIENT_SetAutoReconnect(haveReConnect, new NativeLong(0));

        //设置登录超时时间和尝试次数，可选
        int waitTime = 5000; //登录请求响应超时时间设置为5S
        int tryTimes = 1;    //登录时尝试建立链接1次
        netsdk.CLIENT_SetConnectTime(waitTime, tryTimes);

        // 设置更多网络参数，NET_PARAM的nWaittime，nConnectTryNum成员与CLIENT_SetConnectTime
        // 接口设置的登录设备超时时间和尝试次数意义相同,可选
        NetSDKLib.NET_PARAM netParam = new NetSDKLib.NET_PARAM();
        netParam.nConnectTime = 15000;      // 登录时尝试建立链接的超时时间
        netParam.nGetConnInfoTime = 3000;   // 设置子连接的超时时间
        netsdk.CLIENT_SetNetworkParam(netParam);

        return true;
    }

    /**
     * 登录设备
     * @param ip
     * @param port
     * @param username
     * @param password
     * @return
     */
    public static NativeLong login(String ip,String port,String username,String password){
        NativeLong loginHandle = loginHandleMap.get(ip); //根据ip获取登录句柄
        if(null == loginHandle || loginHandle.longValue() == 0) {
            IntByReference nError = new IntByReference(0);
            loginHandle = netsdk.CLIENT_LoginEx2(ip, Integer.parseInt(port), username, password, 0, null, new NetSDKLib.NET_DEVICEINFO_Ex(), nError);
            if(loginHandle.longValue() == 0) {
                String errorCode = "\n{error code: (0x80000000|" + (netsdk.CLIENT_GetLastError() & 0x7fffffff) +").参考  NetSDKLib.java }"
                        + " - {error info:" + ErrorCode.getErrorCode(netsdk.CLIENT_GetLastError()) + "}\n";
                System.err.printf("Login Device[%s] Port[%d]Failed. %s\n", ip, Integer.parseInt(port), errorCode);
            } else {
                loginHandleMap.put(ip,loginHandle);
                System.out.println("Login Success [ " + ip + " ]");
            }
        }
        return loginHandle;
    }

    /**
     * 登出设备
     * @return
     */
    public static boolean logout(String ip) {
        NativeLong loginHandle = loginHandleMap.get(ip);
        if(loginHandle.longValue() == 0) {
            return false;
        }

        boolean bRet = netsdk.CLIENT_Logout(loginHandle);
        if(bRet) {
            loginHandle.setValue(0);
            loginHandleMap.remove(ip);
        }
        return bRet;
    }

    /**
     * 清除环境
     */
    public static void cleanup() {
        if(bLogopen) {
            netsdk.CLIENT_LogClose();
        }

        if(bInit) {
            netsdk.CLIENT_Cleanup();
        }
    }

    public  boolean openDoor(String ip,String port,String username,String password,short channelId){
        DeviceAPI.init(disConnect, haveReConnect);
        NativeLong loginHandle = login(ip,port,username,password);
        NetSDKLib.ALARMCTRL_PARAM inParam = new NetSDKLib.ALARMCTRL_PARAM();
        inParam.nAlarmNo = channelId;
        inParam.nAction = 1;
        inParam.write();
        boolean flag = netsdk.CLIENT_ControlDevice(loginHandle,
                NetSDKLib.CtrlType.CTRLTYPE_TRIGGER_ALARM_OUT, inParam.getPointer(),3000);
        System.out.println("open door result:"+flag);

        try {
            Thread.sleep(5000l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        NetSDKLib.ALARMCTRL_PARAM closeParam = new NetSDKLib.ALARMCTRL_PARAM();
        closeParam.nAlarmNo = channelId;
        closeParam.nAction = 0;
        closeParam.write();
        flag = netsdk.CLIENT_ControlDevice(loginHandle,
                NetSDKLib.CtrlType.CTRLTYPE_TRIGGER_ALARM_OUT, closeParam.getPointer(),3000);
        System.out.println("close door result:"+flag);
        return flag;
//        System.out.println("test line---------------");
//        return true;
    }

    private static class DisConnect implements NetSDKLib.fDisConnect {
        public void invoke(NativeLong m_hLoginHandle, String pchDVRIP, int nDVRPort, NativeLong dwUser) {
            System.out.printf("Device[%s] Port[%d] DisConnect!\n", pchDVRIP, nDVRPort);
        }
    }

    // 网络连接恢复，设备重连成功回调
    // 通过 CLIENT_SetAutoReconnect 设置该回调函数，当已断线的设备重连成功时，SDK会调用该函数
    private static class HaveReConnect implements NetSDKLib.fHaveReConnect {
        public void invoke(NativeLong m_hLoginHandle, String pchDVRIP, int nDVRPort, NativeLong dwUser) {
            System.out.printf("ReConnect Device[%s] Port[%d]\n", pchDVRIP, nDVRPort);
        }
    }
    /**
     * 测试开门
     * @param args
     */
    public static void main(String[] args) {
//        openDoor("197.175.57.141","37777","admin","admin12345",new Short("0"),new Short("1"));
    }
}
